package cn.wlinker.driver.common;

import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import cn.wlinker.driver.common.utils.IConnectHelper;
import lombok.SneakyThrows;

import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 驱动工厂
 *
 * @author gxsjx
 * @version 1.0
 * @date 2022/9/17
 * Copyright © wlinker.cn
 */
public class DriverFactory {


    private static final Map<String, AbstractDriver<?, ?, ?>> driverMap = new ConcurrentHashMap<>();

    /**
     * 根据连接信息获取驱动
     * @param driverTypeEnum 驱动类型
     * @param connectionMap 连接信息
     * @return 驱动
     */
    @SneakyThrows
    public static AbstractDriver getDriverByConnInfo(IDriverType<?> driverTypeEnum, Map<String, Object> connectionMap) {
        String jsonStr = JSONUtil.toJsonStr(connectionMap);
        String md5Hex = DigestUtil.md5Hex(jsonStr);
        AbstractDriver<?, ?, ?> abstractDriver = driverMap.get(md5Hex);
        if (abstractDriver != null) {
            return abstractDriver;
        }
        Class<? extends AbstractDriver> driver = driverTypeEnum.getDriver();
        Constructor<? extends AbstractDriver> constructor = driver.getConstructor(Map.class);
        abstractDriver = constructor.newInstance(connectionMap);
        String connectionKey = abstractDriver.getConnectionKey();
        driverMap.put(connectionKey, abstractDriver);
        return abstractDriver;
    }

    /**
     * 根据连接信息获取驱动
     * @param cls 驱动类型class
     * @param connectionMap 连接信息
     * @param <T> 驱动类型
     * @return 驱动
     */
    @SneakyThrows
    public static <T extends AbstractDriver> T getDriverByConnInfo(Class<T> cls, Map<String, Object> connectionMap) {
        String jsonStr = JSONUtil.toJsonStr(connectionMap);
        String md5Hex = DigestUtil.md5Hex(jsonStr);
        T abstractDriver = (T) driverMap.get(md5Hex);
        if (abstractDriver != null) {
            return abstractDriver;
        }
        Constructor<T> constructor = cls.getConstructor(Map.class);
        abstractDriver = constructor.newInstance(connectionMap);
        String connectionKey = abstractDriver.getConnectionKey();
        driverMap.put(connectionKey, abstractDriver);
        return abstractDriver;
    }

    /**
     * 根据连接信息获取驱动
     * @param cls 驱动类型class
     * @param connectionMap 连接信息
     * @param connectHelper 连接帮助类
     * @param <T> 驱动类型
     * @return 驱动
     */
    @SneakyThrows
    public static <T extends AbstractDriver> T getDriverByConnInfo(Class<T> cls, Map<String, Object> connectionMap, IConnectHelper connectHelper) {
        String jsonStr = JSONUtil.toJsonStr(connectionMap);
        String md5Hex = DigestUtil.md5Hex(jsonStr);
        T abstractDriver = (T) driverMap.get(md5Hex);
        if (abstractDriver != null) {
            return abstractDriver;
        }
        Constructor<T> constructor = cls.getConstructor(Map.class, IConnectHelper.class);
        abstractDriver = constructor.newInstance(connectionMap, connectHelper);
        String connectionKey = abstractDriver.getConnectionKey();
        driverMap.put(connectionKey, abstractDriver);
        return abstractDriver;
    }

    /**
     * 移除驱动
     */
    public static void removeDriver(String connectionKey) {
        AbstractDriver<?, ?, ?> abstractDriver = driverMap.get(connectionKey);
        if (abstractDriver != null) {
            abstractDriver.close();
            driverMap.remove(connectionKey);
        }
    }
}
